package modelnew;

import java.io.PrintStream;

import modelnew.Field;
import laWa.SusanGame;

// The brain of the game.

// This method calculates a move. It always returns true. The boolean value
// false is reserved for testing and debugging the algorithm and means, that
// the computer doesn't know what to do.
// The move is stored in the computerfrom and computerto variables after
// returning from this method. If the computerfrom value is the Field.magicfield,
// it means that the computer wanted to place a stone on the field specified
// by computerto. Otherwise, the computer decided to move the stone on the
// field given by computerfrom to the field stored in computerto.
// Variables used in the recursive algorithm are declared as instance
// variables instead of passing them in the argument, because this seems to
// be faster an easier.
public class Computer {

	// Data members

	public int computerfrom;
	public int computerto;
	public String computermessage;
	int[] cf;
	int[] cfmark;
	int cfstonescount;
	PrintStream clog;
	int[] cmvfrom;
	int[] cmvto;
	int[] cmvparent;
	int[] cmvpoints;
	int[] cmvcalculate;
	int[] cmvdeepstart;
	int cmvdeepness;
	static final int cmvploose = -1000000000;
	static final int cmvpwin = 1000000000;
	static final int cmvploosebound = -500000000;
	static final int cmvpwinbound = 500000000;
	int cmvnw;
	boolean cmvcanwin;
	int cmvdragcount;
	int cmvstack = 100000;
	static final int cmvminimalstack = 300;
	int[] tree = new int[100];
	int treed, treep;

	SusanGame game;
	Field field;

	public Computer(Field field, SusanGame game) {
		this.field = field;
		this.game = game;

		cf = new int[121];
		cfmark = new int[121];
	}

	public boolean move() {
		computerfrom = Field.magicfield;
		computerto = Field.magicfield;
		int i;

		// Preparations in order to minimize calculation overhead
		cfstonescount = 0;
		for (i = 0; i < 121; i++) {
			cf[i] = field.get(i) ^ game.playturn;
			if ((cf[i] & Field.fieldexoccupied) == Field.fieldexoccupiedyes) {
				cfstonescount++;
				cf[i] &= Field.fieldexoccpl;
			} else {
				cf[i] &= Field.fieldexoccupied;
			}
		}
		if (cmvfrom == null) {
			cmvfrom = new int[cmvstack];
			cmvto = new int[cmvstack];
			cmvparent = new int[cmvstack];
			cmvpoints = new int[cmvstack];
			cmvdeepstart = new int[100];
		}
		cmvfrom[0] = Field.magicfield; // root entry in the tree
		cmvto[0] = Field.magicfield;
		cmvparent[0] = 0;
		cmvpoints[0] = 0;
		cmvdeepstart[0] = 1;
		cmvnw = 1;
		cmvdragcount = game.dragcount;
		treed = 0;
		cmvdeepness = 0;

		// Lay out all possibilities
		ComputerMoveMe(0);
		cmvdeepstart[1] = cmvnw;
		cmvcalculate = new int[cmvnw];

		// Can I win directly?
		if (cmvpoints[0] == cmvpwin) {
			computerfrom = cmvfrom[cmvnw - 1];
			computerto = cmvto[cmvnw - 1];
			computermessage = "Thanks for the game.";

			return true;
		}

		// Recursively calculate possibilities
		ComputerMarkInterestingRoot();
		ComputerTreeCalc();

		// Compare to database
		ComputerTreeMove(0, 0);

		// take one of the best moves
		// check if it is precalc
		while (true) {
			int smax = cmvpoints[1];
			int smaxc = 1;
			int smaxci = 0;
			if (cmvcalculate[1] == 2) {
				smaxci++;
			}
			for (i = 2; i < cmvdeepstart[1]; i++) {
				if (cmvpoints[i] == smax) {
					smaxc++;
					if (cmvcalculate[i] == 2) {
						smaxci++;
					}
				} else if (cmvpoints[i] > smax) {
					smax = cmvpoints[i];
					smaxc = 1;
					smaxci = 0;
					if (cmvcalculate[i] == 2) {
						smaxci++;
					}
				}
			}

			if (smaxci == 0) {
				for (i = 1; i < cmvdeepstart[1]; i++) {
					if (cmvpoints[i] == smax) {
						cmvcalculate[i] = 1;
					}
				}
				ComputerTreeCalc();

			} else {
				int take = (int) (Math.random() * smaxci);
				for (i = 1; i < cmvdeepstart[1]; i++) {
					if ((cmvpoints[i] == smax) && (cmvcalculate[i] == 2)) {
						if (take == 0) {
							computerfrom = cmvfrom[i];
							computerto = cmvto[i];

							if (smax > cmvpwinbound) {
								computermessage = "This move will win.";
							} else if (smax < cmvploosebound) {
								computermessage = "Congratulations, you win.";
							} else {
								computermessage = "Points for this move: "
										+ smax;
							}

							return true;
						}
						take--;
					}
				}
			}
		}
	}

	// Moves to a position in the tree, updating the computerfield
	private void ComputerTreeMove(int treei, int deepness) {
		int treefrom;
		int treeto;
		int wantdeepness = deepness;
		while (treed > deepness) {
			ComputerTreeMoveBack();
		}
		while (deepness > 0) {
			if (treed == deepness) {
				if (tree[deepness] == treei) {
					break;
				}
				ComputerTreeMoveBack();
			}
			tree[deepness] = treei;
			treei = cmvparent[treei];
			deepness--;
		}
		while (treed < wantdeepness) {
			ComputerTreeMoveNext();
		}
	}

	private void ComputerTreeMoveBack() {
		int id = tree[treed];
		int treeto = cmvto[id];
		int treefrom = cmvfrom[id];
		if (treep == 0) {
			treep = 1;
			if (treefrom == Field.magicfield) {
				cf[treeto] = Field.fieldexists;
				cfstonescount--;
			} else {
				cf[treefrom] = cf[treeto];
				cf[treeto] = Field.fieldexists;
			}
		} else {
			treep = 0;
			if (treefrom == Field.magicfield) {
				cf[treeto] = Field.fieldexists;
				cfstonescount--;
			} else {
				cf[treefrom] = cf[treeto];
				cf[treeto] = Field.fieldexists;
			}
		}
		treed--;
	}

	private void ComputerTreeMoveNext() {
		treed++;
		int id = tree[treed];
		int treeto = cmvto[id];
		int treefrom = cmvfrom[id];
		if (treep == 0) {
			treep = 1;
			if (treefrom == Field.magicfield) {
				cf[treeto] = Field.fieldexists | Field.fieldexists;
				cfstonescount++;
			} else {
				cf[treeto] = cf[treefrom];
				cf[treefrom] = Field.fieldexists;
			}
		} else {
			treep = 0;
			if (treefrom == Field.magicfield) {
				cf[treeto] = Field.fieldexists | Field.fieldexists
						| Field.fieldplayer;
				cfstonescount++;
			} else {
				cf[treeto] = cf[treefrom];
				cf[treefrom] = Field.fieldexists;
			}
		}
	}

	// Calculate my possibilities
	private void ComputerMoveMe(int id) {
		cmvcanwin = false;
		int i;
		int n;
		int t;
		if (cmvdragcount < 5) {
			for (i = 0; i < 121; i++) {
				if ((cf[i] & Field.fieldexoccpl) == Field.fieldexoccupiedyes) {
					for (n = 0; n < 6; n++) {
						t = i + field.around[n];
						if ((cf[t] & Field.fieldexoccupied) == Field.fieldexoccupiedno) {
							cf[t] = cf[i];
							cf[i] = Field.fieldexists;
							ComputerMoveMeCheck(id, i, t);
							cf[i] = cf[t];
							cf[t] = Field.fieldexists;
							if (cmvcanwin) {
								cmvpoints[id] = cmvpwin;
								return;
							}
						}
					}
				}
			}
		}

		// Place a stone
		for (i = 0; i < 121; i++) {
			if ((cf[i] & Field.fieldexoccupied) == Field.fieldexoccupiedno) {
				cf[i] = Field.fieldexists | Field.fieldexists;
				ComputerMoveMeCheck(id, Field.magicfield, i);
				cf[i] = Field.fieldexists;
				if (cmvcanwin) {
					cmvpoints[id] = cmvpwin;
					return;
				}
			}
		}
	}

	// Check this move
	private void ComputerMoveMeCheck(int id, int lastfrom, int lastto) {
		int i = lastto;
		int a = 0;
		int n = 0;
		int ret = 0;
		while (true) {
			if ((cf[i] & Field.fieldexoccpl) == Field.fieldexoccupiedyes) {
				for (n = 0; n < 6; n++) {
					if ((cf[i + field.around[n]] & Field.fieldexoccupied) == Field.fieldexoccupiedno) {
						break;
					}
				}
				if (n == 6) {
					return;
				}
			} else if ((cf[i] & Field.fieldexoccpl) == (Field.fieldexoccupiedyes | Field.fieldplayer)) {
				for (n = 0; n < 6; n++) {
					if ((cf[i + field.around[n]] & Field.fieldexoccupied) == Field.fieldexoccupiedno) {
						break;
					}
				}
				if (n == 6) {
					ret = 1;
				}
			}
			if (a == 6) {
				break;
			}
			i = lastto + field.around[a];
			a++;
		}
		if (ret == 0) { // neighter winning nor loosing
			cmvfrom[cmvnw] = lastfrom;
			cmvto[cmvnw] = lastto;
			cmvparent[cmvnw] = id;
			cmvpoints[cmvnw] = ComputerMoveOther(10);
			cmvnw++;
		} else { // winning
			cmvfrom[cmvnw] = lastfrom;
			cmvto[cmvnw] = lastto;
			cmvparent[cmvnw] = id;
			cmvpoints[cmvnw] = cmvpwin;
			cmvnw++;
			cmvcanwin = true;
		}
	}

	// What could my adversaire do in the current situation?
	// This function returns an amount of points for the previous move.
	// If the opponent can win, return cmvploose.
	private int ComputerMoveOther(int pt) {
		int i;
		int n;
		int t;
		if (cmvdragcount < 5) {
			for (i = 0; i < 121; i++) {
				if ((cf[i] & Field.fieldexoccpl) == (Field.fieldexoccupiedyes | Field.fieldplayer)) {
					for (n = 0; n < 6; n++) {
						t = i + field.around[n];
						if ((cf[t] & Field.fieldexoccupied) == Field.fieldexoccupiedno) {
							cf[t] = cf[i];
							cf[i] = Field.fieldexists;
							pt = ComputerMoveOtherCheck(i, t, pt);
							cf[i] = cf[t];
							cf[t] = Field.fieldexists;
							if (pt == cmvploose) {
								return cmvploose;
							}
						}
					}
				}
			}
		}

		// Place a stone
		for (i = 0; i < 121; i++) {
			if ((cf[i] & Field.fieldexoccupied) == Field.fieldexoccupiedno) {
				cf[i] = Field.fieldexists | Field.fieldexists
						| Field.fieldplayer;
				pt = ComputerMoveOtherCheck(Field.magicfield, i, pt);
				cf[i] = Field.fieldexists;
				if (pt == cmvploose) {
					return cmvploose;
				}
			}
		}

		return pt;
	}

	// Check this move
	private int ComputerMoveOtherCheck(int lastfrom, int lastto, int pt) {
		int i = lastto;
		int a = 0;
		int n = 0;
		int ret = 0;
		while (true) {
			if ((cf[i] & Field.fieldexoccpl) == Field.fieldexoccupiedyes) {
				for (n = 0; n < 6; n++) {
					if ((cf[i + field.around[n]] & Field.fieldexoccupied) == Field.fieldexoccupiedno) {
						break;
					}
				}
				if (n == 6) {
					ret = 1;
				}
			} else if ((cf[i] & Field.fieldexoccpl) == (Field.fieldexoccupiedyes | Field.fieldplayer)) {
				for (n = 0; n < 6; n++) {
					if ((cf[i + field.around[n]] & Field.fieldexoccupied) == Field.fieldexoccupiedno) {
						break;
					}
				}
				if (n == 6) {
					return pt;
				} // direct suicide by the other, we assume he doesn't make such
					// a move
			}
			if (a == 6) {
				break;
			}
			i = lastto + field.around[a];
			a++;
		}

		if (ret == 0) { // neither winning nor loosing
						// here we could add some more checks and modify the
						// points
			return pt;
		} else { // winning for the opponent
			return cmvploose;
		}
	}

	public boolean ComputerCalcInterestingFields() {
		int fieldoc = Field.fieldplayer | Field.fieldexists;
		int fieldexoccpl0 = Field.fieldexoccupiedyes;
		int fieldexoccpl1 = Field.fieldexoccupiedyes | Field.fieldplayer;
		int i, n, m, free;
		for (i = 0; i < 121; i++) {
			if ((cf[i] & Field.fieldexoccupied) == Field.fieldexoccupiedyes) {
				int plme = cf[i] & Field.fieldplayer;
				int plother = plme ^ Field.fieldplayer;
				cfmark[i] |= Field.fieldtemp;
				for (n = 0; n < 6; n++) {
					cfmark[i + field.around[n]] |= Field.fieldtemp;
				}
				for (n = 0; n < 6; n++) {
					m = i + field.around[n];
					if (((cf[m] & Field.fieldexoccupied) == Field.fieldexoccupiedno)
							|| ((cf[m] & Field.fieldexoccpl) == (Field.fieldexoccupiedyes | plother))) {
						int w = 0;
						for (; w < 6; w++) {
							if ((cfmark[m + field.around[w]] & Field.fieldtemp) != 0) {
							} else if ((cf[m + field.around[w]] & Field.fieldexists) == 0) {
							} else if ((cf[m + field.around[w]] & Field.fieldexoccpl) == (Field.fieldexoccupiedyes | plme)) {
							} else {
								break;
							}
						}
						if (w == 6) {
							break;
						}
					}
				}
				cfmark[i] = 0;
				if (n != 6) {
					cfmark[i] |= Field.fieldtemp;
				}
				for (n = 0; n < 6; n++) {
					cfmark[i + field.around[n]] ^= Field.fieldtemp;
				}
			} else {
				cfmark[i] = 0;
			}
		}
		for (i = 0; i < 121; i++) {
			if (((cf[i] & Field.fieldexoccupied) == Field.fieldexoccupiedyes)
					&& ((cfmark[i] & Field.fieldtemp) == 0)) {
				free = 0;
				for (n = 0; n < 6; n++) {
					m = i + field.around[n];
					if ((cf[m] & Field.fieldexoccupied) == Field.fieldexoccupiedno) {
						free++;
						if (free == 4) {
							break;
						}
					}
				}
				if (free < 4) {
					cfmark[i] |= Field.fieldmarkcalc;
					for (n = 0; n < 6; n++) {
						m = i + field.around[n];
						cfmark[m] |= Field.fieldmarkcalc;
						if ((cf[m] & Field.fieldexoccupied) == Field.fieldexoccupiedno) {
						}
					}
				}
			}
		}
		return true;
	}

	private boolean ComputerWorthPrecalc(int from, int to) {
		if ((cfmark[to] & Field.fieldmarkcalc) == 0) {
			return ((cfmark[from] & Field.fieldmarkcalc) != 0);
		}
		return true;
	}

	private void ComputerMarkInterestingRoot() {
		ComputerTreeMove(0, 0);
		ComputerCalcInterestingFields();
		for (int i = 1; i < cmvdeepstart[1]; i++) {
			if ((cmvpoints[i] > cmvploosebound)
					&& (cmvpoints[i] < cmvpwinbound)) {
				if (ComputerWorthPrecalc(cmvfrom[i], cmvto[i])) {
					cmvcalculate[i] = 1;
				}
			}
		}
	}

	private void ComputerTreeCalc() {
		cmvnw = cmvdeepstart[1];
		boolean cont = ComputerTreeCalcFirst();
		while (cont) {
			if (!ComputerTreeCalcMe()) {
				ComputerTreeTrack();
				break;
			}
			if (ComputerTreeTrack()) {
				break;
			}
			if (!ComputerTreeCalcOther()) {
				ComputerTreeTrack();
				break;
			}
			if (ComputerTreeTrack()) {
				break;
			}
		}
	}

	private boolean ComputerTreeCalcFirst() {
		int n, i;
		int oldcmvnw = cmvnw;

		cmvdeepness = 1;
		for (i = 1; i < oldcmvnw; i++) {
			if (cmvcalculate[i] == 1) {
				if (cmvnw + cmvminimalstack > cmvstack) {
					return false;
				}
				cmvcalculate[i] = 2;
				ComputerTreeMove(i, 1);
				ComputerCalcInterestingFields();
				ComputerTreeOtherPossibility(i);
			}
		}

		return (oldcmvnw != cmvnw);
	}

	private boolean ComputerTreeCalcMe() {
		int n;
		int i = cmvdeepstart[cmvdeepness];

		int oldcmvnw = cmvnw;
		cmvdeepness++;
		cmvdeepstart[cmvdeepness] = cmvnw;
		int firstchild = 0;

		int oldparent = -1;
		while (i < oldcmvnw) {
			if (cmvnw + cmvminimalstack > cmvstack) {
				return false;
			}
			if (oldparent != cmvparent[i]) {
				ComputerTreeMove(cmvparent[i], cmvdeepness - 1);
				oldparent = cmvparent[i];
			}

			ComputerTreeMove(i, cmvdeepness);
			ComputerCalcInterestingFields();
			firstchild = cmvnw;
			if (ComputerTreeMePossibility(i)) {
				cmvpoints[i] = cmvpwin;
				cmvnw = firstchild;
			}
			i++;
		}
		return (oldcmvnw != cmvnw);
	}

	private boolean ComputerTreeCalcOther() {
		int n;
		int i = cmvdeepstart[cmvdeepness];

		int oldcmvnw = cmvnw;
		cmvdeepness++;
		cmvdeepstart[cmvdeepness] = cmvnw;
		int firstchild = 0;

		int oldparent = -1;
		while (i < oldcmvnw) {
			if (cmvnw + cmvminimalstack > cmvstack) {
				return false;
			}
			if (oldparent != cmvparent[i]) {
				ComputerTreeMove(cmvparent[i], cmvdeepness - 1);
				oldparent = cmvparent[i];
			}

			ComputerTreeMove(i, cmvdeepness);
			ComputerCalcInterestingFields();
			firstchild = cmvnw;
			if (ComputerTreeOtherPossibility(i)) {
				cmvpoints[i] = cmvploose;
				cmvnw = firstchild;
			}
			i++;
		}
		return (oldcmvnw != cmvnw);
	}

	private boolean ComputerTreeTrack() {
		int p = 0;
		int n = cmvnw;
		int id = cmvdeepness;
		if ((id % 2) == 1) {
			ComputerTreeTrackOther(cmvdeepstart[id], n);
			n = cmvdeepstart[id];
			id--;
		}
		while (id > 0) {
			ComputerTreeTrackMe(cmvdeepstart[id], n);
			n = cmvdeepstart[id];
			id--;
			ComputerTreeTrackOther(cmvdeepstart[id], n);
			n = cmvdeepstart[id];
			id--;
		}

		for (int i = 1; i < cmvdeepstart[1]; i++) {
			if (cmvpoints[i] > cmvpwinbound) {
				return true;
			}
		}

		for (int i = cmvdeepstart[1]; i < cmvnw; i++) {
			p = cmvpoints[cmvparent[i]];
			if ((p > cmvpwinbound) || (p < cmvploosebound)) {
				cmvpoints[i] = p;
			}
		}
		return false;
	}

	private void ComputerTreeTrackMe(int first, int i) {
		int oldparent;
		boolean loosing;
		i--;
		while (i >= first) {
			oldparent = cmvparent[i];
			if ((cmvpoints[oldparent] <= cmvpwinbound)
					&& (cmvpoints[oldparent] >= cmvploosebound)) {
				loosing = true;
				while (oldparent == cmvparent[i]) {
					if (cmvpoints[i] > 0) {
						cmvpoints[oldparent] += cmvpoints[i];
						loosing = false;
						break;
					}
					if (cmvpoints[i] == 0) {
						loosing = false;
					}
					i--;
				}
				if (loosing) {
					cmvpoints[oldparent] += cmvpoints[i + 1];
				}
			}
			while (oldparent == cmvparent[i]) {
				i--;
			}
		}
	}

	private void ComputerTreeTrackOther(int first, int i) {
		int oldparent;
		boolean winning;
		i--;
		while (i >= first) {
			oldparent = cmvparent[i];
			if ((cmvpoints[oldparent] <= cmvpwinbound)
					&& (cmvpoints[oldparent] >= cmvploosebound)) {
				winning = true;
				while (oldparent == cmvparent[i]) {
					if (cmvpoints[i] < 0) {
						cmvpoints[oldparent] += cmvpoints[i];
						winning = false;
						break;
					}
					if (cmvpoints[i] == 0) {
						winning = false;
					}
					i--;
				}
				if (winning) {
					cmvpoints[oldparent] += cmvpoints[i + 1];
				}
			}
			while (oldparent == cmvparent[i]) {
				i--;
			}
		}
	}

	private boolean ComputerTreeOtherPossibility(int id) {
		int i;
		int n;
		int t;
		int pt;
		if (cmvdragcount < 5) {
			for (i = 0; i < 121; i++) {
				if ((cf[i] & Field.fieldexoccpl) == (Field.fieldexoccupiedyes | Field.fieldplayer)) {
					for (n = 0; n < 6; n++) {
						t = i + field.around[n];
						if ((cf[t] & Field.fieldexoccupied) == Field.fieldexoccupiedno) {
							cf[t] = cf[i];
							cf[i] = Field.fieldexists;
							pt = ComputerTreeOtherPossibilityCheck(id, i, t);
							cf[i] = cf[t];
							cf[t] = Field.fieldexists;
							if (pt == cmvploose) {
								return true;
							}
						}
					}
				}
			}
		}

		// Place a stone
		for (i = 0; i < 121; i++) {
			if ((cf[i] & Field.fieldexoccupied) == Field.fieldexoccupiedno) {
				cf[i] = Field.fieldexists | Field.fieldexists
						| Field.fieldplayer;
				pt = ComputerTreeOtherPossibilityCheck(id, Field.magicfield, i);
				cf[i] = Field.fieldexists;
				if (pt == cmvploose) {
					return true;
				}
			}
		}

		return false;
	}

	// Check this move
	private int ComputerTreeOtherPossibilityCheck(int id, int lastfrom,
			int lastto) {
		int i = lastto;
		int a = 0;
		int n = 0;
		int ret = 0;
		while (true) {
			if ((cf[i] & Field.fieldexoccpl) == Field.fieldexoccupiedyes) {
				for (n = 0; n < 6; n++) {
					if ((cf[i + field.around[n]] & Field.fieldexoccupied) == Field.fieldexoccupiedno) {
						break;
					}
				}
				if (n == 6) {
					ret = 1;
				}
			} else if ((cf[i] & Field.fieldexoccpl) == (Field.fieldexoccupiedyes | Field.fieldplayer)) {
				for (n = 0; n < 6; n++) {
					if ((cf[i + field.around[n]] & Field.fieldexoccupied) == Field.fieldexoccupiedno) {
						break;
					}
				}
				if (n == 6) {
					return 0;
				} // direct suicide by the other, we assume he doesn't make such
					// a move
			}
			if (a == 6) {
				break;
			}
			i = lastto + field.around[a];
			a++;
		}

		if (ret == 0) { // neighter winning nor loosing
						// here we could add some more checks and modify the
						// points
			if (ComputerWorthPrecalc(lastfrom, lastto)) {
				cmvfrom[cmvnw] = lastfrom;
				cmvto[cmvnw] = lastto;
				cmvparent[cmvnw] = id;
				cmvpoints[cmvnw] = 0;
				cmvnw++;
				return 1;
			} else {
				return 0;
			}
		} else { // winning for the opponent
			return cmvploose;
		}
	}

	private boolean ComputerTreeMePossibility(int id) {
		int i;
		int n;
		int t;
		int pt;
		if (cmvdragcount < 5) {
			for (i = 0; i < 121; i++) {
				if ((cf[i] & Field.fieldexoccpl) == (Field.fieldexoccupiedyes)) {
					for (n = 0; n < 6; n++) {
						t = i + field.around[n];
						if ((cf[t] & Field.fieldexoccupied) == Field.fieldexoccupiedno) {
							cf[t] = cf[i];
							cf[i] = Field.fieldexists;
							pt = ComputerTreeMePossibilityCheck(id, i, t);
							cf[i] = cf[t];
							cf[t] = Field.fieldexists;
							if (pt == cmvpwin) {
								return true;
							}
						}
					}
				}
			}
		}

		// Place a stone
		for (i = 0; i < 121; i++) {
			if ((cf[i] & Field.fieldexoccupied) == Field.fieldexoccupiedno) {
				cf[i] = Field.fieldexists | Field.fieldexists;
				pt = ComputerTreeMePossibilityCheck(id, Field.magicfield, i);
				cf[i] = Field.fieldexists;
				if (pt == cmvpwin) {
					return true;
				}
			}
		}

		return false;
	}

	// Check this move
	private int ComputerTreeMePossibilityCheck(int id, int lastfrom, int lastto) {
		int i = lastto;
		int a = 0;
		int n = 0;
		int ret = 0;
		while (true) {
			if ((cf[i] & Field.fieldexoccpl) == Field.fieldexoccupiedyes) {
				for (n = 0; n < 6; n++) {
					if ((cf[i + field.around[n]] & Field.fieldexoccupied) == Field.fieldexoccupiedno) {
						break;
					}
				}
				if (n == 6) {
					return 0;
				}
			} else if ((cf[i] & Field.fieldexoccpl) == (Field.fieldexoccupiedyes | Field.fieldplayer)) {
				for (n = 0; n < 6; n++) {
					if ((cf[i + field.around[n]] & Field.fieldexoccupied) == Field.fieldexoccupiedno) {
						break;
					}
				}
				if (n == 6) {
					ret = 1;
				}
			}
			if (a == 6) {
				break;
			}
			i = lastto + field.around[a];
			a++;
		}
		if (ret == 0) { // neither winning nor loosing
			if (ComputerWorthPrecalc(lastfrom, lastto)) {
				cmvfrom[cmvnw] = lastfrom;
				cmvto[cmvnw] = lastto;
				cmvparent[cmvnw] = id;
				cmvpoints[cmvnw] = 0;
				cmvnw++;
				return 1;
			} else {
				return 0;
			}
		} else { // winning
			return cmvpwin;
		}
	}

	// Sets the stack size, the most important factor of calculation deepness
	public void setComputerStack(int stacksize) {
		if (stacksize < cmvminimalstack) {
			stacksize = cmvminimalstack;
		}
		cmvstack = stacksize;
	}

	// Returns the stack size
	public int getComputerStack() {
		return cmvstack;
	}
}
